home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_08_06 / 8n06060a < prev    next >
Text File  |  1989-11-08  |  14KB  |  571 lines

  1. /*
  2. **  dates.cpp -- date object methods
  3. */
  4.  
  5.  
  6. #include    <stdio.h>
  7. #include    <stdlib.h>
  8. #include    <math.h>
  9. #include    <dos.h>
  10. #include    <string.h>
  11. #include    "dates.hpp"
  12.  
  13.  
  14. static char ShortMonths[MAXMONTH][4] = {
  15.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  16.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 
  17. };
  18.  
  19. static char LongMonths[MAXMONTH][10] = {
  20.     "January",  "February",  "March",
  21.     "April",    "May",       "June",
  22.     "July",     "August",    "September",
  23.     "October",  "November",  "December"
  24. };
  25.  
  26. static unsigned MonthDays[MAXMONTH] = {
  27.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  28. };
  29.  
  30. static char ShortWeekDays[MAXWEEKDAY+1][4] = {
  31.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  32. };
  33.  
  34. static char LongWeekDays[MAXWEEKDAY+1][10] = {
  35.     "Sunday", "Monday", "Tuesday", "Wednesday",
  36.     "Thursday", "Friday", "Saturday"
  37. };
  38.  
  39. static const char *CurrentDateFormat = "m-dd-yyy";
  40. static int OnHeap = 0;        /* CurrentDateFormat doesn't point to heap */
  41.  
  42.  
  43. /*
  44. **  ChangeDefaultDateFormat -- change the format string used to
  45. **  initialize the DateFormatPtr.  Return 1 on success or 0 if
  46. **  memory could not be allocated for the new string.
  47. */
  48.  
  49. int ChangeDefaultDateFormat(const char *s)
  50. {
  51. char *t;
  52.     
  53.     if ((t = strdup(s)) == NULL)
  54.     return (0);            /* return failure */
  55.     if (OnHeap)
  56.         free(CurrentDateFormat);    /* release old string */
  57.     else
  58.          OnHeap = 1;            /* now we're allocating on heap */
  59.     CurrentDateFormat = t;        /* point to new string */    
  60.     return (1);
  61. }
  62.  
  63.  
  64. /*
  65. **  IsLeap -- return non-zero if Year is a leap year, 0 otherwise.
  66. */
  67.  
  68. static int IsLeap(int Year)
  69. {
  70.   return (Year % 4 == 0) && (Year % 4000 != 0) &&
  71.             ((Year % 100 != 0) || (Year % 400 == 0));
  72. }
  73.  
  74.  
  75. /*
  76. **  DaysInMonth -- return the number of days in Month.  Year
  77. **  is passed to test for a leap year if the month is February.
  78. */
  79.  
  80. static unsigned char DaysInMonth(unsigned char Month, int Year)
  81. {
  82.     if ((Month == 2) && IsLeap(Year))
  83.         return (29);
  84.     else
  85.         return (MonthDays[Month - 1]);
  86. }
  87.  
  88.  
  89. /*
  90. **  CheckForValidDate -- check that Day, Month and Year
  91. **  represent a valid date.  Return non-zero if so, 0 otherwise.
  92. */
  93.  
  94. static int CheckForValidDate(unsigned char Day, unsigned char Month, int Year)
  95. {
  96.     if ((Year < MINYEAR) || (Year > MAXYEAR) || (Year == 0) ||
  97.     (Month < MINMONTH) || (Month > MAXMONTH))
  98.     return (0);
  99.     return (Day <= DaysInMonth(Month, Year));
  100. }
  101.  
  102.  
  103. /*
  104. **  JulianToDayOfWeek -- given a Julian date, return the
  105. **  day of the week for that date, 0 being Sunday, 6 being
  106. **  Saturday.
  107. */
  108.  
  109. static unsigned char JulianToDayOfWeek(long Jul)
  110. {
  111.     return ((Jul + 1) % 7);
  112. }
  113.  
  114.  
  115. /*
  116. **  DMYtoJulian -- after validating the date passed as a Day,
  117. **  Month and Year, convert it to a Julian date.
  118. **
  119. **  The algorithm shown here is swiped directly from "Numerical
  120. **  Recipes in C" by Press, Flannery, Teukolsky and Vettering, p. 10.
  121. */
  122.  
  123. #define    IGREG    (15+31L*(10+12L*1582))
  124.  
  125. static long DMYtoJulian(unsigned char Day, unsigned char Month, int Year)
  126. {
  127. unsigned long Ja, Jm, Jy, Jul;
  128.  
  129.     if (!CheckForValidDate(Day, Month, Year))
  130.     return (BADDATE);
  131.     if (Year < 0)
  132.     Year++;
  133.     if (Month > 2)
  134.     {
  135.     Jy = Year;
  136.     Jm = Month + 1;
  137.     }
  138.     else
  139.     {
  140.     Jy = Year - 1;
  141.     Jm = Month + 13;
  142.     }
  143.     Jul = (long) (floor(365.25*Jy) + floor(30.6001*Jm) + Day + 1720995);
  144.     if (Day + 31L*(Month + 12L*Year) >= IGREG)
  145.     {
  146.     Ja = 0.01*Jy;
  147.     Jul += 2 - Ja + (int) (0.25*Ja);
  148.     }
  149.     return (Jul);
  150. }
  151.  
  152.  
  153. /*  JulianToDMY -- convert a Julian date to the appropriate
  154. **  Day, Month and Year.
  155. **
  156. **  Also swiped from "Numerical Recipes".
  157. */
  158.  
  159. #define    GREGOR    2299161
  160.  
  161. static void JulianToDMY(long Jul, unsigned char *Day, unsigned char *Month, 
  162.     int *Year)
  163. {
  164. long Ja, JAlpha, Jb, Jc, Jd, Je;
  165.  
  166.     if ((Jul != BADDATE) && (Jul >= MINDATE) && (Jul <= MAXDATE))
  167.     {
  168.     if (Jul >= GREGOR)
  169.     {
  170.         JAlpha = ((double) (Jul - 1867216) - 0.25)/36524.25;
  171.         Ja = Jul + 1 + JAlpha - (long) (0.25*JAlpha);
  172.     }
  173.     else
  174.         Ja = Jul;
  175.     Jb = Ja + 1524;
  176.     Jc = 6680.0 + ((double) (Jb - 2439870) - 122.1)/365.25;
  177.     Jd = 365*Jc + (0.25*Jc);
  178.     Je = (Jb - Jd)/30.6001;
  179.     *Day = Jb - Jd - (int) (30.6001*Je);
  180.     *Month = Je - 1;
  181.     if (*Month > 12)
  182.         *Month -= 12;
  183.     *Year = Jc - 4715;
  184.     if (*Month > 2)
  185.         --(*Year);
  186.     if (Year <= 0)
  187.         --(*Year);
  188.     }
  189. }
  190.  
  191.  
  192. /*
  193. **  ChangeDate -- change a date to reflect the new date passed
  194. **  in the arguments.  If the requested date is not a legal date,
  195. **  return a value of 0 without making any changes.  If legal,
  196. **  return 1.  The date format string is not affected.
  197. */
  198.  
  199. int DateObject::ChangeDate(unsigned char NDay, unsigned char NMonth, int NYear)
  200. {
  201. long t;
  202.  
  203.     t = DMYtoJulian(NDay, NMonth, NYear);
  204.     if (t != BADDATE)
  205.     {
  206.         Julian = t;
  207.         Day = NDay;
  208.         Month = NMonth;
  209.         Year = NYear;
  210.         DayOfWeek = JulianToDayOfWeek(Julian);
  211.         return (1);
  212.     }
  213.     return (0);
  214. }
  215.  
  216.  
  217. /*
  218. **  DateObject -- constructor if no args given.  Just initialize
  219. **  to todays date.
  220. */
  221.  
  222. DateObject::DateObject(void)
  223. {
  224. union REGS regs;
  225.  
  226.     regs.x.ax = 0x2a00;        /* DOS get date service */
  227.     intdos(®s, ®s);
  228.     Day = regs.h.dl;
  229.     Month = regs.h.dh;
  230.     Year = regs.x.cx;
  231.     DayOfWeek = regs.h.al;
  232.     Julian = DMYtoJulian(Day, Month, Year);
  233.     DateFormatPtr = strdup(CurrentDateFormat);
  234.     if (DateFormatPtr == NULL)
  235.         Julian = BADDATE;
  236. }
  237.  
  238.  
  239. /*
  240. **  DateObject -- copy initializer constructor
  241. */
  242.  
  243. DateObject::DateObject(DateObject &OtherDate)
  244. {
  245.     Day = OtherDate.Day;
  246.     Month = OtherDate.Month;
  247.     Year = OtherDate.Year;
  248.     DayOfWeek = OtherDate.DayOfWeek;
  249.     Julian = OtherDate.Julian;
  250.     DateFormatPtr = strdup(OtherDate.DateFormatPtr);
  251.     if (DateFormatPtr == NULL)
  252.         Julian = BADDATE;
  253. }
  254.  
  255.  
  256. /*
  257. **  DateObject -- constructor when day, month and year initializers
  258. **  are provided.  The default format string is used.
  259. */
  260.  
  261. DateObject::DateObject(unsigned char InitDay, unsigned char InitMonth,
  262.     int InitYear)
  263. {
  264.     ChangeDate(InitDay, InitMonth, InitYear);
  265.     if (Julian != BADDATE)
  266.     {
  267.     DateFormatPtr = strdup(CurrentDateFormat);
  268.     if (DateFormatPtr == NULL)
  269.         Julian = BADDATE;
  270.     }
  271. }
  272.  
  273.  
  274. /*
  275. **  DateObject -- constructor used when day, month, year and a
  276. **  format string initializer are provided.
  277. */
  278.  
  279. DateObject::DateObject(unsigned char InitDay, unsigned char InitMonth,
  280.     int InitYear, const char *FormatStr)
  281. {
  282.     ChangeDate(InitDay, InitMonth, InitYear);
  283.     if (Julian != BADDATE)
  284.     {
  285.     DateFormatPtr = strdup(FormatStr);
  286.     if (DateFormatPtr == NULL)
  287.         Julian = BADDATE;
  288.     }
  289. }
  290.  
  291.  
  292. /*
  293. **  = -- assignment operator.
  294. */
  295.  
  296. DateObject DateObject::operator = (DateObject &d)
  297. {
  298.     Day = d.Day;
  299.     Month = d.Month;
  300.     Year = d.Year;
  301.     Julian = d.Julian;
  302.     DayOfWeek = d.DayOfWeek;
  303.     DateFormatPtr = strdup(d.DateFormatPtr);
  304.     if (DateFormatPtr == NULL)
  305.         Julian = BADDATE;
  306.     return (*this);
  307. }
  308.  
  309.  
  310. /*
  311. **  + -- addition operator.  This is the fundamental operator
  312. **  function.  All other arithmetic operators returning
  313. **  DateObjects call this function.  The resulting DateObject 
  314. **  copies that format string of the DateObject argument.
  315. */
  316.  
  317. DateObject operator + (DateObject &d, long x)
  318. {
  319. DateObject sum;
  320.  
  321.     sum.Julian = d.Julian + x;
  322.     if ((sum.Julian < MINDATE) || (sum.Julian > MAXDATE))
  323.         sum.Julian = BADDATE;
  324.     else
  325.     {
  326.     JulianToDMY(sum.Julian, &(sum.Day), &(sum.Month), &(sum.Year));
  327.     sum.DayOfWeek = JulianToDayOfWeek(sum.Julian);
  328.     sum.DateFormatPtr = strdup(d.DateFormatPtr);
  329.     if (sum.DateFormatPtr == NULL)
  330.         sum.Julian = BADDATE;
  331.     }
  332.     return (sum);
  333. }
  334.  
  335. DateObject operator + (long x, DateObject &d)
  336. {
  337.     return (d + x);
  338. }
  339.  
  340. DateObject DateObject::operator - (long x)
  341. {
  342.     return (*this + (-x));
  343. }
  344.  
  345. DateObject DateObject::operator ++ (void)
  346. {
  347.     return ((*this) = (*this) + 1L);
  348. }
  349.  
  350. DateObject DateObject::operator -- (void)
  351. {
  352.     return ((*this) = (*this) + (-1L));
  353. }
  354.  
  355. DateObject DateObject::operator += (long x)
  356. {
  357.     return ((*this) = (*this) + x);
  358. }
  359.  
  360. DateObject DateObjec